/**
 * Live GPS Tracking Application
 * Tile provider
 *
 * Copyright 2009, Ivar Clemens
 */

package nl.ivarclemens.gpstrack.tile;

import java.io.*;
import javax.microedition.lcdui.*;
import java.util.Hashtable;
import java.util.Enumeration;

public class TileLoader {

    private WorkerThread thread;
    private boolean allowTransmission = false;

    private Hashtable memoryCache = new Hashtable();

    public TileLoader()
    {
        thread = new WorkerThread(this);
        thread.start();
    }

    public void startTransmission()
    {
        this.allowTransmission = true;
    }

    public void stopTransmission()
    {
        this.allowTransmission = false;
    }

    public boolean mayTransmit()
    {
        return this.allowTransmission;
    }

    /**
     * Puts an item in the cache. The background loader uses this function
     *  to insert tiles into the cache.
     */
    public void insertCache(int x, int y, int zoom, byte[] data)
    {
        String key = "" + zoom + "/" + x + "/" + y;

        // Insert in other caches too

        Image img = Image.createImage(data, 0, data.length);
        memoryCache.put(key, img);
    }

    public Image getTile(int x, int y, int zoom) throws IOException
    {
        byte data[];

        String key = "" + zoom + "/" + x + "/" + y;

        if(memoryCache.containsKey(key))
            return (Image) memoryCache.get(key);

        if(memoryCache.size() > 25)
            memoryCache.clear();

        // Item not in cache, request tile to be downloaded
        if(this.mayTransmit())
            thread.requestTile(x, y, zoom);

        throw new IOException();
    }

    public class WorkerThread extends Thread
    {
        private NetworkSource source = new NetworkSource();

        TileLoader parent;

        /**
         * States:
         *  0 - Idle
         *  1 - Lock 1 (variables are being set)
         *  2 - Ready (download will start soon)
         *  3 - Downloading
         */
        public int state = 0;

        public int x;
        public int y;
        public int zoom;

        public WorkerThread(TileLoader parent)
        {
            this.parent = parent;
        }

        public void requestTile(int x, int y, int zoom)
        {
            if(state != 0)
                return;

            state = 1;
            this.x = x;
            this.y = y;
            this.zoom = zoom;
            state = 2;
        }

        public void run()
        {
            while(true) {
                if(state == 2 && parent.mayTransmit()) {
                    state = 3;

                    try {
                        byte[] data = source.loadTile(x, y, zoom);
                        parent.insertCache(x, y, zoom, data);
                    } catch(Exception e) {
                    }

                    state = 0;
                } else {
                    try {
                        Thread.sleep(2000);
                    } catch(Exception e) {
                    }
                }
            }
        }
    }
}
